package org.hujunfeng.http;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @Author 胡俊丰
 * @Date 2024/8/5
 * <p>
 * 定义字节缓冲阅读器
 **/
public class BuffReader extends InputStream {

    /**
     * 定义对底层输入流的引用
     */
    private InputStream input;

    /**
     * 定义字节缓冲数组
     */
    private byte[] buff = new byte[2024];

    /**
     * 队头指针
     */
    private int head = 0;

    /**
     * 队尾指针
     */
    private int rear = 0;

    /**
     * 记录当前总共的缓冲数据个数
     */
    private int length = 0;

    /**
     * 构造方法
     *
     * @param inputStream
     */
    public BuffReader(InputStream inputStream) {
        this.input = inputStream;
    }

    public InputStream getInputStream() {
        return this.input;
    }

    /**
     * 复制数据
     *
     * @param target 目标数组
     * @param src    源数组
     * @param size
     */
    private void copy(byte[] target, byte[] src, int size) {
        for (int k = 0; k < size; k++) {
            this.rear = (rear + 1) % buff.length;
            target[rear] = src[k];
        }
    }

    /**
     * 读取一个字节
     *
     * @return
     */
    public synchronized int read() throws IOException {
        // 1、缓冲没有数据
        if (length <= 0) {
            // 1.1、调用底层流读取
            byte[] temp = new byte[getFreeSpace()];

            // 1.2、读取一次
            int size = input.read(temp, 0, temp.length);

            // 1.3、如果读取到数据
            if (size > 0) {
                // 复制数据到缓冲
                copy(buff, temp, size);

                // 记录个数
                length = length + size;
            }

            // 1.4、如果读取结束，返回-1
            if (size == -1) {
                return -1;
            }
        }

        // 2、如果缓冲有数据
        if (length > 0) {
            // 队头指针循环加一
            head = (head + 1) % buff.length;

            // 获取队头元素
            int data = buff[head] & 0xFF;

            // 长度减一
            length--;

            // 返回队头元素
            return data;
        }
        return -1;
    }

    /**
     * 读取字节块
     *
     * @return
     */
    public synchronized int read(byte[] data, int offset, int size) throws IOException {
        // 1、如果缓冲没有数据
        if (length <= 0){
            // 1.1、调用底层流读取
            byte[] temp = new byte[getFreeSpace()];

            int count = input.read(temp, 0, temp.length);

            // 如果读取结束，返回-1
            if (count == -1){
                return -1;
            }

            // 如果读取到数据
            if (count > 0) {
                // 复制数据到缓冲
                copy(buff, temp, count);

                // 记录个数
                length = length + count;
            }
        }

        // 2、缓冲有数据
        if (length > 0) {
            int min = 0;

            // 获得最小的字节数
            if (length < size){
                min = length;
            } else {
                min = size;
            }

            // 优先使用缓冲的数据
            for (int k = 0; k < min; k++) {
                this.head = (head + 1) % buff.length;
                data[offset + k] = buff[head];
                length--;
            }

            // 返回个数
            return min;
        }

        // 3、返回默认值-1
        return -1;
    }

    /**
     * 读取一行，返回字符串
     *
     * @param charset
     * @return
     */
    public synchronized String readLine(String separator, String charset) throws IOException {
        byte[] line = readLine(separator);

        if (line == null) {
            return null;
        }
        return new String(line, charset);
    }

    /**
     * 读取一行，是\r\n换行
     *
     * @param separator 换行符
     * @return 存放一行字节的数组
     */
    public synchronized byte[] readLine(String separator) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        boolean isEOF = false;

        // 1、进入循环
        while (true) {
            // 1.1、查找缓冲空间内部是否存在第一个换行符
            int index = findEnd(buff, length, separator.charAt(0));

            // 1.2、如果大于-1，代表存在
            if (index > -1) {
                // 1.2.1、把缓冲的数据写入输出流
                for (int k = 1; k < index; k++) {
                    head = (head + 1) % buff.length;
                    length--;
                    baos.write(buff[head]);
                }

                // 1.2.2、跳过回车符
                head = (head + 1) % buff.length;
                length--;

                // 1.2.3、如果后面还有分隔符
                if (separator.length() > 1) {
                    for (int i = 1; i <= separator.length() - 1; i++) {
                        // 如果有缓冲数据，就读取一个
                        if (getLength() > 0) {
                            head = (head + 1) % buff.length;
                            length--;
                        } else {
                            // 从底层输入流读取字节
                            input.read();
                        }
                    }
                }

                // 1.2.4、跳出循环
                break;
            } else {
                // 1.3、把缓冲的数据写入输出流
                int totalLength = getLength();
                for (int k = 1; k <= totalLength; k++) {
                    head = (head + 1) % buff.length;
                    length--;
                    baos.write(buff[head]);
                }

                // 1.4、定义临时数组
                byte[] temp = new byte[getFreeSpace()];

                // 1.5、读取一个剩余大小的空间
                int size = input.read(temp, 0, temp.length);

                // 1.6、处理数据
                if (size > 0) {
                    // 复制数据到缓冲
                    copy(buff, temp, size);

                    // 记录个数
                    length = length + size;
                } else if (size == -1) {
                    isEOF = true;
                    break;
                }
            }
        }

        // 2、如果本次没有读取数据
        if(baos.size() == 0) {
            // 2.1、如果已经关闭
            if (isEOF) {
                // 返回空
                return null;
            }
        }

        // 3、返回缓冲的字节数组
        return baos.toByteArray();
    }

    /**
     * 找第一个分隔符的索引位置，找不到就返回-1；
     *
     * @return
     */
    private int findEnd(byte[] data, int length, char c) {
        int index = -1;
        int temp = 0;
        for (int k = 1; k <= length; k++) {
            temp = (head + k) % buff.length;
            if (data[temp] == c) {
                index = k;
                break;
            }
        }
        return index;
    }

    /**
     * 判断是否超出缓冲空间
     *
     * @return 布尔值
     */
    private boolean isFull() {
        if (head == (rear + 1) % buff.length) {
            return true;
        }
        return false;
    }

    /**
     * 判断缓冲是否为空
     *
     * @return 如果为空，返回真，否则返回假
     */
    private boolean isEmpty() {
        if (head == rear) {
            return true;
        }
        return false;
    }

    /**
     * 返回当前缓冲的数据长度
     *
     * @return
     */
    private int getLength() {
        return this.length;
    }

    /**
     * 获取当前缓冲剩余的空间
     *
     * @return
     */
    private int getFreeSpace() {
        return buff.length - length - 1;
    }

    /**
     * 关闭输入流
     */
    public synchronized void close() throws IOException{
        buff = null;
        input.close();
    }
}

